package com.piece.mall.service;

import com.piece.core.framework.constant.ExceptionConstants;
import com.piece.core.framework.enums.StatusType;
import com.piece.core.framework.support.convert.Convert;
import com.piece.core.framework.support.response.AjaxResponse;
import com.piece.core.pay.client.PayClient;
import com.piece.core.pay.client.PayClientFactory;
import com.piece.core.pay.dto.*;
import com.piece.core.pay.enums.PayNotifyRefundStatusType;
import com.piece.mall.api.enums.OrderStatusType;
import com.piece.mall.api.enums.RefundStatusType;
import com.piece.mall.model.OmsOrder;
import com.piece.mall.model.OmsPaymentInfo;
import com.piece.mall.model.OmsRefundInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;

@Slf4j
@Service
@Transactional
public class PaymentService {

    @Resource
    private PayClientFactory payClientFactory;

    @Resource
    private OmsOrderService omsOrderService;

    @Resource
    private OmsPaymentInfoService omsPaymentInfoService;

    @Resource
    private OmsRefundInfoService omsRefundInfoService;

    @Resource
    private OmsOrderReturnApplyService omsOrderReturnApplyService;

    /**
     * 支付操作
     * @param channel  付款渠道
     * @param code     渠道类别
     * @param payOrder 统一下单请求数据
     */
    public AjaxResponse payoff(String channel, String code, PayOrderUnifiedReqDTO payOrder) {
        payOrder.setAmount(payOrder.getAmount() * 100);
        PayClient payClient = payClientFactory.getPayClient(channel, code);
        return payClient.unifiedOrder(payOrder);
    }

    /**
     * 支付回调
     * @param channel  付款渠道
     * @param code     渠道类别
     * @param notifyData  通知请求数据
     */
    public AjaxResponse payNotify(String channel, String code, PayNotifyDataDTO notifyData) throws Exception {
        PayClient payClient = payClientFactory.getPayClient(channel, code);
        PayOrderNotifyRespDTO response = payClient.parseOrderNotify(notifyData);
        return paySuccess(response, channel, code);
    }

    /**
     * 支付成功
     * @param response 支付查询数据
     */
    public AjaxResponse paySuccess(PayOrderNotifyRespDTO response, String channel, String channelCode) throws Exception {
        String status = response.getTradeStatus();
        String orderSn = response.getOrderExtensionNo();
        OmsOrder omsOrder = omsOrderService.findByOrderSn(orderSn);
        if ("TRADE_SUCCESS".equals(status) && !OrderStatusType.PAYED.getCode().equals(omsOrder.getStatus())) {
            // 保存交易信息
            OmsPaymentInfo paymentInfo = new OmsPaymentInfo();
            paymentInfo.setOrderId(omsOrder.getId());
            paymentInfo.setOrderSn(orderSn);
            paymentInfo.setChannelTradeNo(response.getChannelOrderNo());
            paymentInfo.setTotalAmount(response.getAmount());
            paymentInfo.setPaymentSubject(response.getData());
            paymentInfo.setPaymentStatus(OrderStatusType.PAYED.getCode());
            paymentInfo.setPaymentChannel(channel);
            paymentInfo.setPaymentChannelCode(channelCode);
            paymentInfo.setCallbackTime(response.getSuccessTime());
            paymentInfo.setCreateTime(new Date());
            omsPaymentInfoService.insert(paymentInfo);
            // 更新订单状态
            omsOrderService.changeOrderStatusByOrderSn(orderSn, OrderStatusType.COMPLETE);
            return AjaxResponse.success(ExceptionConstants.MESSAGE_SUCCESS, response);
        } else {
            return AjaxResponse.error(ExceptionConstants.MESSAGE_ERROR, response);
        }
    }

    /**
     * 退款操作
     * @param channel  付款渠道
     * @param code     渠道类别
     * @param refundOrder 统一退款请求数据
     */
    public AjaxResponse refund(String channel, String code, PayRefundUnifiedReqDTO refundOrder) {
        PayClient payClient = payClientFactory.getPayClient(channel, code);
        // 查询订单支付信息
        PayOrderNotifyRespDTO payOrder = payClient.tradeUnifiedQuery(refundOrder.getPayTradeNo());
        if ("TRADE_SUCCESS".equals(payOrder.getTradeStatus())) {
            refundOrder.setChannelOrderNo(payOrder.getChannelOrderNo());
            refundOrder.setAmount(refundOrder.getAmount() * 100);
            return payClient.unifiedRefund(refundOrder);
        } else {
            return AjaxResponse.error(payOrder.getData());
        }
    }

    /**
     * 退款回调
     * @param channel  付款渠道
     * @param code     渠道类别
     * @param notifyData  通知请求数据
     */
    public AjaxResponse refundNotify(String channel, String code, PayNotifyDataDTO notifyData) throws Exception {
        PayClient payClient = payClientFactory.getPayClient(channel, code);
        PayRefundNotifyDTO response = payClient.parseRefundNotify(notifyData);
        return refundSuccess(response, channel, code);
    }

    /**
     * 退款成功
     * @param response 退款查询数据
     */
    public AjaxResponse refundSuccess(PayRefundNotifyDTO response, String channel, String channelCode) throws Exception {
        PayNotifyRefundStatusType status = response.getStatus();
        // 保存交易流水号
        OmsRefundInfo refundInfo = new OmsRefundInfo();
        refundInfo.setOrderSn(response.getTradeNo());
        refundInfo.setRefundSn(response.getReqNo());
        refundInfo.setRefundAmount(response.getAmount());
        refundInfo.setRefundChannel(channel);
        refundInfo.setRefundChannelCode(channelCode);
        if (PayNotifyRefundStatusType.SUCCESS.equals(status)) {
            refundInfo.setRefundStatus(StatusType.SUCCESS.getCode());
            omsRefundInfoService.insert(refundInfo);
            // 更新退款申请单状态
            omsOrderReturnApplyService.changeStatus(Convert.toLong(response.getReqNo()), RefundStatusType.SEND_OUT.getCode());
            return AjaxResponse.success(ExceptionConstants.MESSAGE_SUCCESS, response);
        } else {
            refundInfo.setRefundStatus(StatusType.FAIL.getCode());
            omsRefundInfoService.insert(refundInfo);
            return AjaxResponse.error(ExceptionConstants.MESSAGE_ERROR, response);
        }
    }
}
